package com.zlk.learning.bytebuddy;

import com.alibaba.fastjson.JSONObject;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.matcher.ElementMatchers;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;

import static sun.tools.java.RuntimeConstants.ACC_PRIVATE;
import static sun.tools.java.RuntimeConstants.ACC_VOLATILE;


public class Example001 {

    public static void main(String[] args) throws Exception {
        DynamicType.Builder<?> dynamicBuilder = new ByteBuddy()
                .subclass(Object.class)
                .defineField("proxyContext1", Object.class, ACC_PRIVATE | ACC_VOLATILE)
                .implement(EnhancedInterface.class)
                .intercept(FieldAccessor.ofField("proxyContext1"));

        outputClazz(dynamicBuilder.make()
                .load(Example001.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                .getBytes());
        Class<?> dynamicClass = dynamicBuilder.make()
                .load(Example001.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                .getLoaded();

//        Method[] methods = dynamicClass.getDeclaredMethods();
//        for (Method method : methods) {
//            System.out.println(method.getName());
//        }

        EnhancedInterface enhancedInterface = (EnhancedInterface) dynamicClass.newInstance();
        enhancedInterface.setProxyContextxx("123");
        System.out.println(enhancedInterface.test());

        enhancedInterface.setProxyContext("467");
        System.out.println(enhancedInterface.getProxyContextxx());
        System.out.println(enhancedInterface.getProxyContextxx());


        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .name("com.zlk.learning.bytebuddy.DynamicType")
                .defineField("name", String.class, 1)
                .defineField("age", Integer.class, 1)
                .method(ElementMatchers.named("toString"))
                .intercept(FixedValue.value("Hello World!"))
                .make();
        dynamicClass = dynamicType
                .load(Object.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        System.out.println(dynamicClass.getName());
        Object object = JSONObject.parseObject("{'name': 'zhoulk', 'age': 23}", dynamicClass);
        Field[] fields = dynamicClass.getFields();
        for (Field field : fields) {
            System.out.println(field.getName() + " = " + field.get(object));
        }
        System.out.println(object);
    }

    private static void outputClazz(byte[] bytes) {
        FileOutputStream out = null;
        try {
            String pathName = Example001.class.getResource("/").getPath() + "ByteBuddyHelloWorld.class";
            out = new FileOutputStream(new File(pathName));
            System.out.println("类输出路径：" + pathName);
            out.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
